use crate::error::Result;
use std::any::Any;
use std::collections::HashSet;
use fxhash::FxHashMap;

/// Base trait for all Redis data types
/// 
/// This trait defines the core interface that all Redis data types must implement.
/// It provides type introspection through the Any trait.
pub trait DataType: Send + Sync + Any + std::fmt::Debug {
    /// Get the type name as a string (e.g., "string", "hash", "list")
    fn type_name(&self) -> &'static str;
    
    /// Get a string representation of the value for debugging
    fn debug_string(&self) -> String;
    
    /// Clone the data type (used for deep copying)
    fn clone_data(&self) -> Box<dyn DataType>;
    
    /// Check if the data type is empty
    fn is_empty(&self) -> bool;
    
    /// Get the memory usage in bytes (approximate)
    fn memory_usage(&self) -> usize;
    
    /// Downcast to Any for type checking
    fn as_any(&self) -> &dyn Any;
    
    /// Mutable downcast to Any for type checking
    fn as_any_mut(&mut self) -> &mut dyn Any;
}

/// Trait for counter operations (INCR, DECR, etc.)
/// 
/// Implemented by StringType for numeric strings
pub trait CounterOperations: DataType {
    /// Increment the value by the given amount
    fn increment(&mut self, amount: i64) -> Result<i64>;
    
    /// Decrement the value by the given amount  
    fn decrement(&mut self, amount: i64) -> Result<i64>;
    
    /// Get the current numeric value
    fn get_numeric_value(&self) -> Result<i64>;
    
    /// Set the numeric value
    fn set_numeric_value(&mut self, value: i64) -> Result<()>;
}

/// Trait for hash operations (HSET, HGET, etc.)
/// 
/// Implemented by HashType
pub trait HashOperations: DataType {
    /// Set a field-value pair in the hash
    fn hset(&mut self, field: String, value: String) -> Result<bool>;
    
    /// Get the value of a field
    fn hget(&self, field: &str) -> Result<Option<String>>;
    
    /// Delete a field from the hash
    fn hdel(&mut self, field: &str) -> Result<bool>;
    
    /// Check if a field exists
    fn hexists(&self, field: &str) -> Result<bool>;
    
    /// Get all field names
    fn hkeys(&self) -> Result<Vec<String>>;
    
    /// Get all values
    fn hvals(&self) -> Result<Vec<String>>;
    
    /// Get all field-value pairs
    fn hgetall(&self) -> Result<FxHashMap<String, String>>;
    
    /// Get the number of fields
    fn hlen(&self) -> Result<usize>;
    
    /// Set multiple field-value pairs
    fn hmset(&mut self, pairs: FxHashMap<String, String>) -> Result<()>;
    
    /// Get multiple field values
    fn hmget(&self, fields: &[String]) -> Result<Vec<Option<String>>>;
}

/// Trait for list operations (LPUSH, RPOP, etc.)
/// 
/// Implemented by ListType
pub trait ListOperations: DataType {
    /// Push elements to the left (head) of the list
    fn lpush(&mut self, values: Vec<String>) -> Result<usize>;
    
    /// Push elements to the right (tail) of the list
    fn rpush(&mut self, values: Vec<String>) -> Result<usize>;
    
    /// Pop an element from the left (head) of the list
    fn lpop(&mut self) -> Result<Option<String>>;
    
    /// Pop an element from the right (tail) of the list
    fn rpop(&mut self) -> Result<Option<String>>;
    
    /// Get the length of the list
    fn llen(&self) -> Result<usize>;
    
    /// Get an element by index
    fn lindex(&self, index: i64) -> Result<Option<String>>;
    
    /// Set an element by index
    fn lset(&mut self, index: i64, value: String) -> Result<()>;
    
    /// Get a range of elements
    fn lrange(&self, start: i64, stop: i64) -> Result<Vec<String>>;
    
    /// Trim the list to the specified range
    fn ltrim(&mut self, start: i64, stop: i64) -> Result<()>;
    
    /// Remove elements equal to value
    fn lrem(&mut self, count: i64, value: &str) -> Result<usize>;
    
    /// Insert element before or after pivot
    fn linsert(&mut self, before: bool, pivot: &str, value: String) -> Result<i64>;
}

/// Trait for set operations (SADD, SREM, etc.)
/// 
/// Implemented by SetType
pub trait SetOperations: DataType {
    /// Add members to the set
    fn sadd(&mut self, members: Vec<String>) -> Result<usize>;
    
    /// Remove members from the set
    fn srem(&mut self, members: &[String]) -> Result<usize>;
    
    /// Check if a member exists in the set
    fn sismember(&self, member: &str) -> Result<bool>;
    
    /// Get all members of the set
    fn smembers(&self) -> Result<HashSet<String>>;
    
    /// Get the number of members in the set
    fn scard(&self) -> Result<usize>;
    
    /// Get random members from the set
    fn srandmember(&self, count: Option<i64>) -> Result<Vec<String>>;
    
    /// Pop a random member from the set
    fn spop(&mut self, count: Option<usize>) -> Result<Vec<String>>;
    
    /// Get the union of multiple sets
    fn sunion(&self, other_sets: &[&dyn SetOperations]) -> Result<HashSet<String>>;
    
    /// Get the intersection of multiple sets
    fn sinter(&self, other_sets: &[&dyn SetOperations]) -> Result<HashSet<String>>;
    
    /// Get the difference between sets
    fn sdiff(&self, other_sets: &[&dyn SetOperations]) -> Result<HashSet<String>>;
}

/// Trait for sorted set operations (ZADD, ZREM, etc.)
/// 
/// Implemented by SortedSetType
pub trait SortedSetOperations: DataType {
    /// Add members with scores to the sorted set
    fn zadd(&mut self, members: Vec<(f64, String)>) -> Result<usize>;
    
    /// Remove members from the sorted set
    fn zrem(&mut self, members: &[String]) -> Result<usize>;
    
    /// Get the score of a member
    fn zscore(&self, member: &str) -> Result<Option<f64>>;
    
    /// Get the rank of a member (0-based, lowest score first)
    fn zrank(&self, member: &str) -> Result<Option<usize>>;
    
    /// Get the reverse rank of a member (0-based, highest score first)
    fn zrevrank(&self, member: &str) -> Result<Option<usize>>;
    
    /// Get the number of members in the sorted set
    fn zcard(&self) -> Result<usize>;
    
    /// Count members within a score range
    fn zcount(&self, min: f64, max: f64) -> Result<usize>;
    
    /// Get members by rank range
    fn zrange(&self, start: i64, stop: i64, with_scores: bool) -> Result<Vec<(String, Option<f64>)>>;
    
    /// Get members by reverse rank range
    fn zrevrange(&self, start: i64, stop: i64, with_scores: bool) -> Result<Vec<(String, Option<f64>)>>;
    
    /// Get members by score range
    fn zrangebyscore(&self, min: f64, max: f64, with_scores: bool, limit: Option<(usize, usize)>) -> Result<Vec<(String, Option<f64>)>>;
    
    /// Get members by reverse score range
    fn zrevrangebyscore(&self, max: f64, min: f64, with_scores: bool, limit: Option<(usize, usize)>) -> Result<Vec<(String, Option<f64>)>>;
    
    /// Remove members by rank range
    fn zremrangebyrank(&mut self, start: i64, stop: i64) -> Result<usize>;
    
    /// Remove members by score range
    fn zremrangebyscore(&mut self, min: f64, max: f64) -> Result<usize>;
    
    /// Increment the score of a member
    fn zincrby(&mut self, increment: f64, member: &str) -> Result<f64>;
}